﻿using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Dynamic;

namespace Ruandao.MiniAccess
{
    /// <summary>
    /// 
    /// </summary>
    public interface IAccess
    {
        /// <summary>
        /// 是否处于调试状态，调试状态下总是重新创建所有需要的数据库对象，如存储过程等。
        /// </summary>
        bool IsDebug { get; }

        /// <summary>
        /// 获取数据库对象。
        /// </summary>
        /// <returns>返回数据库对象。</returns>
        Database GetDatabase();

        /// <summary>
        /// 连接字符串的名字。改名字来自配置文件中的connectionString元素。
        /// </summary>
        string ConnectionString { get; }

        /// <summary>
        /// 实现IAccessProvider的数据存取类型，如SqlServer、MySql和Sqlite等。
        /// </summary>
        string AccessType { get; }

        /// <summary>
        /// 根据主键删除数据库中某个实体记录的数据。
        /// <br/>异常：NotSupportException(表没有主键、或映射表中显式设定删除命令为空串)。
        /// DbException(删除数据为反数据库中设定的约束)
        /// </summary>
        /// <param name="keys">主键。</param>
        /// <returns>实际删除的记录数量，如果指定主键的记录不存在返回0。</returns>
        int DeleteEntity<T>(params object[] keys);

        /// <summary>
        /// 根据条件在数据库中删除实体。
        /// <br/>异常：NotSupportException(映射表中显式设定条件删除命令为空串)。
        /// DbException(删除数据违反数据库中设定的约束)
        /// </summary>
        /// <param name="conditions">包括 WHERE关键字的条件字符串。</param>
        /// <returns>实际删除实体的数量，如果没有满足条件的记录则返回0。</returns>
        /// <remarks>
        /// 条件字符串是实际数据库能够支持的SELECT语句的子句，包括 WHERE, ORDER BY等关键字。
        /// 可以包括INNER JOIN...AS等联结关系的表达，完成多表查询。
        /// </remarks>
        int DeleteEntities<T>(string conditions);

        /// <summary>
        /// 把一个实体保存到数据库中。
        /// <br/>异常：NotSupportException(映射表中显式设定条件插入命令为空串)。
        /// DbException(插入数据时违反数据库中设定的约束)
        /// </summary>
        /// <param name="t">所要保存的实体。</param>
        /// <remarks>
        /// 注意：在执行返回后，像标识列等无需提供值的字段将作为输出参数用来填充
        /// 实体t中的属性值。直接在映射文件中提供SQL语句时需要考虑到这一点。
        /// 注意该函数没有返回值，根据是否抛出异常判断插入是否成功。
        /// </remarks>
        int InsertEntity<T>(T t) where T : IEntity,new();

        /// <summary>
        /// 更新数据库中的记录数据。
        /// <br/>异常：NotSupportException(表没有主键，或映射表中显式设定更新命令为空串)。
        /// DbException(更新数据时违反数据库中设定的约束)
        /// </summary>
        /// <param name="t">所要更新的实体。</param>
        /// <param name="keys">主键。</param>
        /// <returns>实际修改的记录数量，如果指定主键的记录不存在返回0。</returns>
        int UpdateEntity<T>(T t, params object[] keys) where T : IEntity,new();

        /// <summary>
        /// 根据条件在数据库中查找实体。
        /// </summary>
        /// <param name="condition">带WHERE字符串的查询条件。</param>
        /// <returns>查找到的实体列表。如果没有查找到任何实体，返回长度为0的列表。</returns>
        /// <remarks>条件字符串是实际数据库能够支持的SELECT语句的子句，包括 WHERE, ORDER BY等关键字。
        /// 可以包括INNER JOIN...AS等联结关系的表达，完成多表查询。
        /// </remarks>
        IList<T> SearchEntities<T>(string condition) where T : IEntity,new();

        /// <summary>
        /// 根据主键读取记录并创建实体对象，允许返回null。
        /// </summary>
        /// <param name="keys">主键。</param>
        /// <returns>返回得到的实体，如果没有查到实体，返回null，而不是抛出异常。</returns>
        T FetechEntity<T>(params object[] keys) where T : IEntity,new();

        /// <summary>
        /// 根据条件查找记录并创建实体对象，允许返回null。
        /// </summary>
        /// <param name="condition">查询条件。</param>
        /// <returns>返回查到的第一个实体，如果没有查到则返回null。</returns>
        T FindEntity<T>(string condition) where T : IEntity,new();

        /// <summary>
        /// 读取数据库中一条记录的内容到实体中。
        /// </summary>
        /// <param name="t">存放读取出来的数据的实体。</param>
        /// <param name="reader">指向一条记录。</param>
        void LoadFromReader<T>(T t, IDataReader reader) where T : IEntity,new();

        /// <summary>
        /// 和LoadFromReader&lt;T>的区别在于返回的是动态对象，而不是把把数据装载到泛型参数指定的实例中。
        /// </summary>
        /// <param name="reader"></param>
        /// <returns></returns>
        ExpandoObject FetchObject(string commandText, DbParameter[] parameters);
        ExpandoObject FetchObject(string storedProcedureName, params object[] parameterValues);

        /// <summary>
        /// 依次读出reader结果集中的数据，以动态对象列表的形式返回所有的数据。
        /// </summary>
        /// <param name="reader"></param>
        /// <returns></returns>
        IList<ExpandoObject> FetchObjectList(string commandText, DbParameter[] parameters);
        IList<ExpandoObject> FetchObjectList(string storedProcedureName, params object[] parameterValues);

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        string[] GetKeyPropertyNames<T>() where T : IEntity,new();

        /// <summary>
        /// 创建存储过程。如果isDebug为false, 则仅当存储过程不存在时在重新创建。
        /// </summary>
        /// <param name="procedureName">存储过程名称。</param>
        /// <param name="parametersText">声明参数的代码段。</param>
        /// <param name="bodyText">存储过程中的执行代码段。</param>
        void CreateProcedure(string procedureName, string parametersText, string bodyText);

        /// <summary>
        /// 
        /// </summary>
        /// <param name="commandText"></param>
        /// <param name="parameters"></param>
        /// <returns></returns>
        int ExecuteNonQuery(string commandText, params DbParameter[] parameters);

        /// <summary>
        /// 
        /// </summary>
        /// <param name="commandText"></param>
        /// <param name="parameters"></param>
        /// <returns></returns>
        object ExecuteScalar(string commandText, params DbParameter[] parameters);

        /// <summary>
        /// 
        /// </summary>
        /// <param name="commandText"></param>
        /// <param name="parameters"></param>
        /// <returns></returns>
        IDataReader ExecuteReader(string commandText, params DbParameter[] parameters);
        
        /// <summary>
        /// 
        /// </summary>
        /// <param name="storedProcedureName"></param>
        /// <param name="parameterValues"></param>
        /// <returns></returns>
        object ExecuteScalar(string storedProcedureName, params object[] parameterValues);

        /// <summary>
        /// 
        /// </summary>
        /// <param name="storedProcedureName"></param>
        /// <param name="parameterValues"></param>
        /// <returns></returns>
        IDataReader ExecuteReader(string storedProcedureName, params object[] parameterValues);

        /// <summary>
        /// 
        /// </summary>
        /// <param name="storedProcedureName"></param>
        /// <param name="parameterValues"></param>
        /// <returns></returns>
        int ExecuteNonQuery(string storedProcedureName, params object[] parameterValues);

    }
}
